﻿using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using GN.Pay.TradeChannel.Exceptions;
using System.Globalization;
using System.Numerics;
using GN.Pay.Utils.Security;
using GN.Pay.TradeChannel.DefaultImpl;
using GN.Pay.TradeChannel.Configure;

namespace GN.Pay.TradeChannel.UnionPay
{
    public static class SecurityUtils
    {
        private static HashAlgorithm Hash_Algorithm = new SHA1CryptoServiceProvider();

        /// <summary>
        /// 摘要计算
        /// </summary>
        /// <param name="dataStr"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        private static byte[] Sha1X16(string dataStr, Encoding encoding)
        {
            byte[] data = encoding.GetBytes(dataStr);
            using (SHA1 sha1 = new SHA1CryptoServiceProvider())
            {
                byte[] sha1Res = sha1.ComputeHash(data, 0, data.Length);
                return sha1Res;
            }
        }

        /// <summary>
        /// 获取签名证书提供程序
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static RSACryptoServiceProvider GetSignProvider(ChannelPfxSignConfigureInfo info)
        {
            var raw = info.SignPfxRaw();
            if (raw == null)
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "UnionPay", "未配置签名Pfx");
            }
            if (string.IsNullOrWhiteSpace(info.SignPfxPassWord))
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "UnionPay", "未配置签名Pfx的密码");
            }
            return RsaUtils.PrivateKeyProvider(raw, info.SignPfxPassWord);
        }

        /// <summary>
        /// 获取签名验证证书提供程序
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static RSACryptoServiceProvider GetSignVerifyProvider(ChannelPfxSignConfigureInfo info)
        {
            if (string.IsNullOrWhiteSpace(info.SignVerifyCerRawBase64))
            {
                throw new TradeChannelException(TradeChannelErrorCode.Configure, "UnionPay", "未配置签名验证公钥 PaySignVerifyCerRawBase64 ");
            }
            return RsaUtils.PublicKeyProvider(info.SignVerifyCerRaw());
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="config"></param>
        /// <param name="dataStr"></param>
        /// <returns></returns>

        public static string Sign(ChannelPfxSignConfigureInfo configureInfo, string dataStr)
        {
            using (var provider = GetSignProvider(configureInfo))
            {
                byte[] signDigest = Sha1X16(dataStr, Encoding.UTF8);
                string stringSignDigest = BitConverter.ToString(signDigest).Replace("-", "").ToLower();
                byte[] data = Encoding.UTF8.GetBytes(stringSignDigest);
                byte[] res = provider.SignData(data, Hash_Algorithm);
                return Convert.ToBase64String(res);
            }
        }

        /// <summary>
        /// 验签
        /// </summary>
        /// <param name="config"></param>
        /// <param name="sign"></param>
        /// <param name="sourceContext"></param>
        /// <returns></returns>
        public static bool SignVerify(ChannelPfxSignConfigureInfo configureInfo, string sign, string sourceContext)
        {
            using (var provider = GetSignVerifyProvider(configureInfo))
            {
                byte[] signByte = Convert.FromBase64String(sign);
                byte[] signDigest = Sha1X16(sourceContext, Encoding.UTF8);
                string stringSignDigest = BitConverter.ToString(signDigest).Replace("-", "").ToLower();
                byte[] srcData = Encoding.UTF8.GetBytes(stringSignDigest);
                return provider.VerifyData(srcData, Hash_Algorithm, signByte);
            }
        }
    }
}
